package server.demo.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import server.demo.dto.CreateTrainRequest;
import server.demo.dto.TrainDTO;
import server.demo.dto.TransferRouteDTO;
import server.demo.dto.TransferSearchRequest;
import server.demo.entity.Station;
import server.demo.entity.Train;
import server.demo.entity.Ticket;
import server.demo.repository.StationRepository;
import server.demo.repository.TrainRepository;
import server.demo.repository.TicketRepository;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Transactional
public class TrainService {
    
    @Autowired
    private TrainRepository trainRepository;
    
    @Autowired
    private StationRepository stationRepository;
    
    @Autowired
    private TicketRepository ticketRepository;
    
    public List<TrainDTO> getAllTrains() {
        return trainRepository.findAll().stream()
                .map(TrainDTO::new)
                .collect(Collectors.toList());
    }
    
    public Optional<TrainDTO> getTrainById(Long id) {
        return trainRepository.findById(id)
                .map(TrainDTO::new);
    }
    
    public Optional<TrainDTO> getTrainByNumber(String trainNumber) {
        return trainRepository.findByTrainNumber(trainNumber)
                .map(TrainDTO::new);
    }
    
    public List<TrainDTO> searchTrains(Long startStationId, Long endStationId, LocalDate travelDate) {
        return trainRepository.findAvailableTrains(startStationId, endStationId, travelDate)
                .stream()
                .map(TrainDTO::new)
                .collect(Collectors.toList());
    }
    
    public TrainDTO createTrain(CreateTrainRequest request) {
        if (trainRepository.existsByTrainNumber(request.getTrainNumber())) {
            throw new RuntimeException("车次号已存在: " + request.getTrainNumber());
        }
        
        Optional<Station> startStation = stationRepository.findById(request.getStartStationId());
        Optional<Station> endStation = stationRepository.findById(request.getEndStationId());
        
        if (startStation.isEmpty()) {
            throw new RuntimeException("起始站不存在");
        }
        
        if (endStation.isEmpty()) {
            throw new RuntimeException("终点站不存在");
        }
        
        Train train = new Train();
        train.setTrainNumber(request.getTrainNumber());
        train.setTrainType(Train.TrainType.valueOf(request.getTrainType()));
        train.setStartStation(startStation.get());
        train.setEndStation(endStation.get());
        train.setDepartureTime(request.getDepartureTime());
        train.setArrivalTime(request.getArrivalTime());
        train.setTravelDate(request.getTravelDate());
        train.setStatus(Train.TrainStatus.ACTIVE);
        
        Train savedTrain = trainRepository.save(train);
        return new TrainDTO(savedTrain);
    }
    
    public TrainDTO updateTrain(Long id, CreateTrainRequest request) {
        Optional<Train> trainOpt = trainRepository.findById(id);
        if (trainOpt.isEmpty()) {
            throw new RuntimeException("车次不存在");
        }
        
        Train train = trainOpt.get();
        
        if (!train.getTrainNumber().equals(request.getTrainNumber()) && 
            trainRepository.existsByTrainNumber(request.getTrainNumber())) {
            throw new RuntimeException("车次号已存在: " + request.getTrainNumber());
        }
        
        Optional<Station> startStation = stationRepository.findById(request.getStartStationId());
        Optional<Station> endStation = stationRepository.findById(request.getEndStationId());
        
        if (startStation.isEmpty()) {
            throw new RuntimeException("起始站不存在");
        }
        
        if (endStation.isEmpty()) {
            throw new RuntimeException("终点站不存在");
        }
        
        train.setTrainNumber(request.getTrainNumber());
        train.setTrainType(Train.TrainType.valueOf(request.getTrainType()));
        train.setStartStation(startStation.get());
        train.setEndStation(endStation.get());
        train.setDepartureTime(request.getDepartureTime());
        train.setArrivalTime(request.getArrivalTime());
        train.setTravelDate(request.getTravelDate());
        
        Train savedTrain = trainRepository.save(train);
        return new TrainDTO(savedTrain);
    }
    
    public void cancelTrain(Long id) {
        Optional<Train> trainOpt = trainRepository.findById(id);
        if (trainOpt.isEmpty()) {
            throw new RuntimeException("车次不存在");
        }
        
        Train train = trainOpt.get();
        train.setStatus(Train.TrainStatus.CANCELLED);
        trainRepository.save(train);
    }
    
    public void deleteTrain(Long id) {
        if (!trainRepository.existsById(id)) {
            throw new RuntimeException("车次不存在");
        }
        
        // 检查是否有相关的票务记录
        List<Ticket> relatedTickets = ticketRepository.findByTrainId(id);
        if (!relatedTickets.isEmpty()) {
            throw new RuntimeException("无法删除车次：该车次存在" + relatedTickets.size() + "张相关票务记录。请先处理相关票务。");
        }
        
        trainRepository.deleteById(id);
    }
    
    /**
     * 查询换乘路线
     */
    public List<TransferRouteDTO> searchTransferRoutes(TransferSearchRequest request) {
        List<TransferRouteDTO> transferRoutes = new ArrayList<>();
        
        // 获取所有可能的中转站
        List<Station> allStations = stationRepository.findAll();
        
        for (Station transferStation : allStations) {
            // 跳过起点站和终点站
            if (transferStation.getId().equals(request.getStartStationId()) || 
                transferStation.getId().equals(request.getEndStationId())) {
                continue;
            }
            
            // 查询第一段：起点->中转站
            List<Train> firstSegmentTrains = trainRepository.findAvailableTrains(
                request.getStartStationId(), 
                transferStation.getId(), 
                request.getTravelDate()
            );
            
            // 查询第二段：中转站->终点
            List<Train> secondSegmentTrains = trainRepository.findAvailableTrains(
                transferStation.getId(), 
                request.getEndStationId(), 
                request.getTravelDate()
            );
            
            // 匹配合适的换乘组合
            for (Train firstTrain : firstSegmentTrains) {
                for (Train secondTrain : secondSegmentTrains) {
                    // 检查换乘时间是否合理
                    if (isValidTransfer(firstTrain, secondTrain, request.getMaxTransferWait())) {
                        TransferRouteDTO route = createTransferRoute(
                            firstTrain, secondTrain, transferStation, request
                        );
                        if (route != null) {
                            transferRoutes.add(route);
                        }
                    }
                }
            }
        }
        
        // 按总耗时排序
        return transferRoutes.stream()
                .sorted((r1, r2) -> Integer.compare(r1.getTotalDuration(), r2.getTotalDuration()))
                .collect(Collectors.toList());
    }
    
    /**
     * 检查换乘是否有效
     */
    private boolean isValidTransfer(Train firstTrain, Train secondTrain, Integer maxTransferWait) {
        LocalTime firstArrival = firstTrain.getArrivalTime();
        LocalTime secondDeparture = secondTrain.getDepartureTime();
        
        // 计算换乘等待时间
        long waitMinutes;
        if (secondDeparture.isAfter(firstArrival)) {
            waitMinutes = Duration.between(firstArrival, secondDeparture).toMinutes();
        } else {
            // 第二趟车是第二天的，加24小时
            waitMinutes = Duration.between(firstArrival, secondDeparture.plusHours(24)).toMinutes();
        }
        
        // 至少要有30分钟换乘时间，最多不超过设定的最大等待时间
        return waitMinutes >= 30 && waitMinutes <= maxTransferWait;
    }
    
    /**
     * 创建换乘路线DTO
     */
    private TransferRouteDTO createTransferRoute(Train firstTrain, Train secondTrain, 
                                               Station transferStation, TransferSearchRequest request) {
        try {
            TrainDTO firstTrainDTO = new TrainDTO(firstTrain);
            TrainDTO secondTrainDTO = new TrainDTO(secondTrain);
            
            // 计算换乘等待时间
            LocalTime waitTime = calculateWaitTime(firstTrain.getArrivalTime(), secondTrain.getDepartureTime());
            
            // 计算总耗时（分钟）
            int totalDuration = calculateTotalDuration(firstTrain, secondTrain);
            
            // 计算总价格（这里简化处理，实际应该根据座位类型和里程计算）
            BigDecimal totalPrice = BigDecimal.valueOf(100.0 + Math.random() * 200); // 简化的价格计算
            
            return new TransferRouteDTO(
                firstTrainDTO,
                secondTrainDTO,
                transferStation.getId(),
                transferStation.getStationName(),
                waitTime,
                totalDuration,
                totalPrice
            );
        } catch (Exception e) {
            // 如果创建过程中出现异常，返回null
            return null;
        }
    }
    
    /**
     * 计算换乘等待时间
     */
    private LocalTime calculateWaitTime(LocalTime firstArrival, LocalTime secondDeparture) {
        if (secondDeparture.isAfter(firstArrival)) {
            long minutes = Duration.between(firstArrival, secondDeparture).toMinutes();
            return LocalTime.of((int)(minutes / 60), (int)(minutes % 60));
        } else {
            // 跨天的情况
            long minutes = Duration.between(firstArrival, secondDeparture.plusHours(24)).toMinutes();
            return LocalTime.of((int)(minutes / 60), (int)(minutes % 60));
        }
    }
    
    /**
     * 计算总耗时
     */
    private int calculateTotalDuration(Train firstTrain, Train secondTrain) {
        // 第一段耗时
        long firstDuration = Duration.between(firstTrain.getDepartureTime(), firstTrain.getArrivalTime()).toMinutes();
        if (firstDuration < 0) firstDuration += 24 * 60; // 跨天的情况
        
        // 第二段耗时
        long secondDuration = Duration.between(secondTrain.getDepartureTime(), secondTrain.getArrivalTime()).toMinutes();
        if (secondDuration < 0) secondDuration += 24 * 60; // 跨天的情况
        
        // 换乘等待时间
        long waitDuration = Duration.between(firstTrain.getArrivalTime(), secondTrain.getDepartureTime()).toMinutes();
        if (waitDuration < 0) waitDuration += 24 * 60; // 跨天的情况
        
        return (int) (firstDuration + waitDuration + secondDuration);
    }
}